/* page.tsx spboucher.ai Web Author: Simon-Pierre Boucher Mail: contact@spboucher.ai */ import type { Metadata } from "next"; import Image from "next/image"; import Link from "next/link"; import { notFound } from "next/navigation"; import { ArrowLeft, Award, BookOpen, Download, ExternalLink, Github, Layers, Sparkles, Tag, Workflow, } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { buttonVariants } from "@/components/ui/button"; import { Card, CardHeader } from "@/components/ui/card"; import { IconTile } from "@/components/icon-tile"; import { Reveal } from "@/components/reveal"; import { SectionHeading } from "@/components/section-heading"; import { getAllProjectLinks, type ProjectLinks } from "@/lib/apps"; import { getDetailIcon } from "@/lib/detail-icons"; import { projectDetails } from "@/lib/project-details"; interface PageProps { params: Promise<{ slug: string }>; } function getProject(slug: string): ProjectLinks | undefined { return getAllProjectLinks().find((p) => p.slug === slug); } export function generateStaticParams() { return getAllProjectLinks() .filter((p) => projectDetails.some((d) => d.slug === p.slug)) .map((p) => ({ slug: p.slug })); } export async function generateMetadata({ params, }: PageProps): Promise { const { slug } = await params; const project = getProject(slug); const detail = projectDetails.find((d) => d.slug === slug); if (!project || !detail) return {}; return { title: `${project.name} — ${project.tagline}`, description: detail.hero.subheadline, }; } export default async function ProjectDetailPage({ params }: PageProps) { const { slug } = await params; const project = getProject(slug); const detail = projectDetails.find((d) => d.slug === slug); if (!project || !detail) notFound(); const statCols = detail.stats.length <= 3 ? "sm:grid-cols-3" : detail.stats.length === 4 ? "sm:grid-cols-2 lg:grid-cols-4" : detail.stats.length === 5 ? "sm:grid-cols-3 lg:grid-cols-5" : "sm:grid-cols-3 lg:grid-cols-6"; return (
{/* Back link */} {/* Hero */}
{project.icon ? ( {`${project.name} ) : ( )}
{project.kind === "zyquo" ? "Zyquo macOS Suite" : project.demo ? "Web Platform" : "Open Source"} {project.language && ( {project.language} )}

{project.name}

{detail.hero.headline}

{detail.hero.subheadline}

{project.release && ( )} {project.demo && ( )} {project.dmg && ( )}
{/* Stats band */} {detail.stats.length > 0 && (
{detail.stats.map((stat) => (

{stat.value}

{stat.label}

))}
)} {/* Overview */}
{detail.overview.map((paragraph) => (

{paragraph}

))}
{/* Features */} {detail.features.length > 0 && (
{detail.features.map((feature, i) => (

{feature.title}

{feature.description}

))}
)} {/* How it works */} {detail.architecture.length > 0 && (
    {detail.architecture.map((step, i) => (
  1. {step.title}

    {step.description}

  2. ))}
)} {/* Tech stack */} {detail.techStack.length > 0 && (
{detail.techStack.map((group, i) => (

{group.category}

{group.items.map((item) => ( {item} ))}
))}
)} {/* Highlights */} {detail.highlights.length > 0 && (
    {detail.highlights.map((highlight, i) => (
  • ))}
)} {/* CTA */}

Explore {project.name}

{project.tagline} — the full source is on GitHub.

{project.demo && ( )} {project.dmg && ( )}
); }